<?php

declare(strict_types=1);

namespace GSC\Server;

use GSC\Core;
use GSC\Config;
use GSC\Context;
use GSC\CoreConst;
use GSC\Listener;
use GSC\Route;
use Swoole\Server;
use Swoole\Http\Server as HttpServer;
use Swoole\Process;
use Swoole\Http\Request;
use Swoole\Http\Response;

class Http
{
    protected $_server;

    protected $_config;

    protected $_route;

    public function start()
    {
        $config        = Config::getInstance()->get('servers', []);
        $httpConfig    = $config['http'];
        $this->_config = $httpConfig;

        $this->_server = new HttpServer(
            $httpConfig['ip'],
            $httpConfig['port'],
            $config['mode'],
            $httpConfig['sock_type']
        );

        $this->_server->on('WorkerStart', [$this, 'onWorkerStart']);
        $this->_server->on('Request', [$this, 'onRequest']);
        $this->_server->set($httpConfig['settings']);

        if ($config['mode'] == SWOOLE_BASE) {
            $this->_server->on('managerStart', [$this, 'onManagerStart']);
        } else {
            $this->_server->on('start', [$this, 'onStart']);
        }

        foreach ($httpConfig['callbacks'] as $eventKey => $callbackItem) {
            [$class, $func] = $callbackItem;
            $this->_server->on($eventKey, [$class, $func]);
        }

        if (isset($this->_config['process']) && !empty($this->_config['process'])) {
            foreach ($this->_config['process'] as $processItem) {
                [$class, $func] = $processItem;
                $this->_server->addProcess($class::$func($this->_server));
            }
        }

        $this->_server->start();
    }

    public function stop()
    {
        $pidFile = Config::getInstance()->get('servers.http.settings.pid_file');
        if (empty($pidFile)) {
            throw new \RuntimeException("pid_file not setting");
        }
        $pid = file_get_contents($pidFile);
        Process::kill((int)$pid);
    }

    public function onStart(Server $server)
    {
        Core::echoSuccess("Swoole Http Server running：http://{$this->_config['ip']}:{$this->_config['port']}");
        Listener::getInstance()->listen('start', $server);
    }

    public function onManagerStart(Server $server)
    {
        Core::echoSuccess("Swoole Http Server running：http://{$this->_config['ip']}:{$this->_config['port']}");
        Listener::getInstance()->listen('managerStart', $server);
    }

    public function onWorkerStart(Server $server, int $workerId)
    {
        $this->_route = Route::getInstance();
        Listener::getInstance()->listen('workerStart', $server, $workerId);
    }

    public function onRequest(Request $request, Response $response)
    {
        Context::set(CoreConst::SW_REQUEST, $request);
        Context::set(CoreConst::SW_RESPONSE, $response);
        $this->_route->dispatch($request, $response);
    }
}
